<?php
/*
 *  avisaro wlan modul 2.0 command line tools
 *  Copyright (C) 2009 Daniel Werner, Mark Schmale
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
	
class avisaro extends simpleSocket 
{
    protected $cmdInternal = array( 'MAN'       => 'cmdMan',  
                                    'QUIT'      => 'cmdQuit',
                                    'UPLOAD'    => 'cmdLoad',
                                    'ALIAS'     => 'cmdAddAlias',
                                    'LICENSE'   => 'cmdLicense');

    protected $cmdAlias    = array( 'LS'        => 'LIST');

    /**
     * Creates a nice process bar for cli
     *
     * @author Daniel Werner <daniel@werner-plettenberg.de>
     * @author Mark Schmale <ma.schmale@googlemail.com>
     * @param integer $current current value of the process
     * @param integer $total maximum value of the process
     * @param string  $type optional name of the process
     * @param integer $bar_len optional lenght of the process bar
     */
    public function showProcessBar($current, $total, $type=null, $bar_len=40)
    {
        $prozent        = ($current / $total * 100);
        $num_len        = strlen($countl);
        $bar_show_len   = floor($prozent / 100 * $bar_len);
        $bar_noshow_len = $bar_len - $bar_show;
        $bar_show       = str_repeat('|', $bar_show_len);
        $bar_noshow     = str_repeat(' ', $bar_noshow_len);
        $bar_percent    = sprintf('%4d', $prozent);
        echo '['.$bar_show.$bar_noshow.'] '.$bar_percent.'% ';
        if($type != null)
        {
            $type_cnt = sprintf('%'.($num_len+1).'d', $linenum);
            echo ' '.$type.' '.$type_cnt.' of '.$total;
        }
        echo "\r";
    }

    /**
     * uploads a scriptfile to the avisaro 
     *
     * @author Daniel Werner <daniel@werner-plettenberg.de>
     * @author Mark Schmale <ma.schmale@googlemail.com>
     * @param string $filename path to the file that should be loaded
     */
    public function loadScript($filename)
    {
        $content = file($filename);
        $countl = count($content);
        echo "Uploading Script ".$filename." - ".$countl." Line(s)".PHP_EOL;			     
        $this->writeLine('LOAD');
        usleep(50000);
        $linenum = 0;
        foreach($content as $line) 
        {
            $linenum++;
            $this->showProcessBar($linenum, $countl, 'Line');
            $this->writeLine($line);
            usleep(10000); // we need this delay becaus the avisaro is some kind of fucked up
        }
        usleep(50000);
        $this->writeLine('++++');
        echo PHP_EOL.'done'.PHP_EOL;
    }
    
    /**
     * starts the loaded script
     * 
     * @author Daniel Werner <daniel@werner-plettenberg.de>
     */
    public function runScript()
    {
        $this->writeLine('RUN');
    }
    
    /**
     * gets the version string of avisaro
     * 
     * @author Daniel Werner <daniel@werner-plettenberg.de>
     * @returns string
     */
    public function getVer()
    {
        $this->writeLine('VER?');
        return trim($this->readLine());
    }
    
    /**
     * reads available commands from avisaro
     *
     * @author Daniel Werner <daniel@werner-plettenberg.de>
     * @author Mark Schmale <ma.schmale@googlemail.com>
     */
    private function cacheCommands()
    {
        echo 'caching commands: ';
        $this->writeLine('CMDS?');
        do {
            $b = $this->readByte();
            $cmds .= $b;
        } while($b != '>');
        $this->cmdAvisaro = explode(', ', $cmds);
        $this->updateCompletion();
        echo 'done'.PHP_EOL;
    }

    /**
     * reads errormessages from avisaro
     *
     * @author Daniel Werner <daniel@werner-plettenberg.de>
     * @author Mark Schmale <ma.schmale@googlemail.com>
     */
    private function cacheErrors()
    {
        echo 'caching errors: ';
        $this->writeLine("ERRORS?");
        do {
            $b = $this->readByte();
            $errors .= $b;
        } while($b != '>');
        $errors = explode(', ', $errors);
        unset($errors[count($errors)-1]);
        foreach($errors as $error) {
            $reg = array();
            preg_match('@\(([0-9]{1,3})\) (.*)@', $error, $reg);
            $errnr  = $reg[1];
            $errmsg = $reg[2];
            $this->errTranslation[$errnr] = $errmsg;
        }
        echo 'done'.PHP_EOL;
    }

    private function updateCompletion()
    {
        $this->cmdAll = array_merge($this->cmdAvisaro, array_keys($this->cmdInternal), array_keys($this->cmdAlias));
    }

    public function cliStart()
    {
        $this->loop = true;
        $this->cacheErrors();
        $this->cacheCommands();
        readline_callback_handler_install('', array($this, 'cliCallback'));
        readline_read_history(".avisaro/history");
        readline_completion_function(array($this, 'cliCompletion'));
        $this->cliMainLoop();
    }

    private function cliCompletion($in)
    {
        return $this->cmdAll;
    }

    /**
     * prints the LICENSE-File
     *
     * @author Mark Schmale <ma.schmale@googlemail.com>
     */
    private function cmdLicense()
    {
        readfile('./LICENSE');
    }

    
    /**
     * gives help for a given command
     *
     * @author Mark Schmale <ma.schmale@googlemail.com>
     * @param string $cmd command yow want help for
     */
    private function cmdMan($cmd)
    {
        $file = ".avisaro/commands/".strtoupper($cmd);
        if(file_exists($file)) {
            echo file_get_contents($file).PHP_EOL;
        } else {
            echo "I dont know this Command!".PHP_EOL;
        }
    }

    /**
     * terminates the shell
     *
     * @author Mark Schmale <ma.schmale@googlemail.com>
     */
    private function cmdQuit()
    {
        echo "Good Bye".PHP_EOL;
        $this->loop = false;
    }

    private function cmdLoad($param)
    {
        if(file_exists($param)) $con->loadScript($param);
        else echo "File ".$param." not found!".PHP_EOL;
    }


    private function cliCallback($line)
    {
        readline_add_history($line);
        $this->cliHandleLine($line);

    }

    private function cliHandleLine($line)
    {
        $cmds = cliParser::parse($line);
        foreach($cmds as $cmd_data)
        {
            $cmd  = $cmd_data['cmd'];
            $para = $cmd_data['param'];
           /** if(!in_array($cmd, $this->cmdAll))
            {
                echo 'Command not found'.PHP_EOL;
                return;
            } **/
            if(isset($this->cmdAlias[$cmd]))
            {
                // got an alias 
                $this->cliHandleLine($this->cmdAlias[$cmd].' '.implode(' ', $para));
            } else if(isset($this->cmdInternal[$cmd])) {
                // got an internal
                if(!is_array($this->cmdInternal[$cmd]))
                {
                    $cb = array($this, $this->cmdInternal[$cmd]);
                } else {
                    $cb = $this->cmdInternal[$cmd];
                }
                call_user_func_array($cb, $para);
            } else {
                // got an avisaro funtion
                $this->writeLine($cmd.' '.implode(' ', $para));
            }
        }
    }

    private function cliMainLoop()
    {
        echo 'READY: '.PHP_EOL;
        while($this->loop)
        {
            $read   = array(STDIN, $this->fp);
            $write  = null;
            $except = null;
            $return = stream_select($read, $write, $except, NULL);
            if(in_array(STDIN, $read))
            {
                readline_callback_read_char();
            }
            if(in_array($this->fp, $read))
            {
                echo $this->readByte();
            }
        }
    }
}
?>
